HOST = null; // localhost
PORT = 8001;

// when the daemon started
var starttime = (new Date()).getTime();

var mem = process.memoryUsage();
// every 10 seconds poll for the memory.
setInterval(function () {
    mem = process.memoryUsage();
}, 10*1000);


var fu  = require("./fu"),
sys     = require("sys"),
url     = require("url"),
http    = require("http"),
qs      = require("querystring");

var MESSAGE_BACKLOG = 200,
SESSION_TIMEOUT = 60 * 1000;


var channel = new function () {
    var messages  = [],
    callbacks = [];

    this.appendMessage = function (nick, type, text) {
        var m = {
            nick: nick
            , 
            type: type // "msg", "join", "part"
            , 
            text: text
            , 
            timestamp: (new Date()).getTime()
        };

        switch (type) {
            case "msg":
                //sys.puts("<" + nick + "> " + text);
                break;
            case "join":
                //sys.puts(nick + " join");
                break;
            case "part":
                //sys.puts(nick + " part");
                break;
        }

        messages.push( m );

        while (callbacks.length > 0) {
            callbacks.shift().callback([m]);
        }

        while (messages.length > MESSAGE_BACKLOG)
            messages.shift();
    };

    this.query = function (since, callback) {
        var matching = [];
        for (var i = 0; i < messages.length; i++) {
            var message = messages[i];
            if (message.timestamp > since)
                matching.push(message)
        }

        if (matching.length != 0) {
            callback(matching);
        } else {
            callbacks.push({
                timestamp: new Date(), 
                callback: callback
            });
        }
    };

    // clear old callbacks
    // they can hang around for at most 30 seconds.
    setInterval(function () {
        var now = new Date();
        while (callbacks.length > 0 && now - callbacks[0].timestamp > 30*1000) {
            callbacks.shift().callback([]);
        }
    }, 3000);
};


var sessions = {};


function createSession (ID) {
//if (nick.length > 50) return null;
//if (/[^\w_\-^!]/.exec(nick)) return null;
/*
  for (var i in sessions) {
    var session = sessions[i];
    if (session && session.nick === nick) {
        session.poke();
        ID = session.id;
    }
        //return null;
  }
  */
    
            
 
    
}


// interval to kill off old sessions
setInterval(function () {
    var now = new Date();
    for (var id in sessions) {
        if (!sessions.hasOwnProperty(id)) continue;
        var session = sessions[id];

        if (now - session.timestamp > SESSION_TIMEOUT) {
            session.destroy();
        }
    }
}, 1000);


fu.listen(Number(process.env.PORT || PORT), HOST);

fu.get("/", fu.staticHandler("index.html"));
fu.get("/style.css", fu.staticHandler("style.css"));
fu.get("/client.js", fu.staticHandler("client.js"));
fu.get("/jquery-1.2.6.min.js", fu.staticHandler("jquery-1.2.6.min.js"));

fu.get("/who", function (req, res) {
    var nicks = [];
    for (var id in sessions) {
        if (!sessions.hasOwnProperty(id)) continue;
        var session = sessions[id];
        nicks.push(session.nick);
    }
    res.simpleJSON(200, {
        nicks: nicks
        , 
        rss: mem.rss
    });
});

fu.get("/join", function (req, res) {
    var ID = qs.parse(url.parse(req.url).query).ID;
    //var nick = qs.parse(url.parse(req.url).query).nick;
    if (ID == null || ID.length == 0) {
        res.simpleJSON(400, {
            error: "Bad ID."
        });
        return;
    }
    //var session = createSession(ID);
    
    
    var options = {
        host: 'socially.im',
        port: 80,
        path: '/chat/join/TOKEN' + ID
    };

    http.get(options, function(r) {
        r.setEncoding('utf8');
        r.on('data',function(chunk) {
            console.log(chunk);
            var nick = chunk;
            if (nick == null || nick.length == 0) {
                return null;
            }
            var session = { 
                'nick': nick, 
                id: ID,
                //id: ID || Math.floor(Math.random()*99999999999).toString(),
                timestamp: new Date(),

                poke: function () {
                    session.timestamp = new Date();
                },

                destroy: function () {
                    channel.appendMessage(session.nick, "part");
                    delete sessions[session.id];
                }
            };
            sessions[session.id] = session;
            if (session == null) {
                res.simpleJSON(400, {
                    error: "Nick in use"
                });
                return;
            }
            console.log(session);
            //sys.puts("connection: " + nick + "@" + res.connection.remoteAddress);
            channel.appendMessage(session.nick, "join");
            res.simpleJSON(200, {
                id: session.id
                , 
                nick: session.nick
                , 
                rss: mem.rss
                , 
                starttime: starttime
            });
        });
    }).on('error', function(e) {
        return null;
        console.log("Got error: " + e.message);
    });
});

fu.get("/part", function (req, res) {
    var id = qs.parse(url.parse(req.url).query).id;
    var session;
    if (id && sessions[id]) {
        session = sessions[id];
        session.destroy();
    }
    res.simpleJSON(200, {
        rss: mem.rss
    });
});

fu.get("/recv", function (req, res) {
    if (!qs.parse(url.parse(req.url).query).since) {
        res.simpleJSON(400, {
            error: "Must supply since parameter"
        });
        return;
    }
    var id = qs.parse(url.parse(req.url).query).id;
    var session;
    if (id && sessions[id]) {
        session = sessions[id];
        session.poke();
    }

    var since = parseInt(qs.parse(url.parse(req.url).query).since, 10);

    channel.query(since, function (messages) {
        if (session) session.poke();
        res.simpleJSON(200, {
            messages: messages, 
            rss: mem.rss
        });
    });
});

fu.get("/send", function (req, res) {
    var id = qs.parse(url.parse(req.url).query).id;
    var text = qs.parse(url.parse(req.url).query).text;

    var session = sessions[id];
    if (!session || !text) {
        res.simpleJSON(400, {
            error: "No such session id"
        });
        return;
    }

    session.poke();

    channel.appendMessage(session.nick, "msg", text);
    res.simpleJSON(200, {
        rss: mem.rss
    });
});
